package com.server.questionbank.snframe.service.CourseService.Impl;

import com.server.questionbank.snframe.domain.Course.Chapter.*;
import com.server.questionbank.snframe.domain.Course.Resource.CourseFiles;
import com.server.questionbank.snframe.domain.Course.Resource.CourseResource;
import com.server.questionbank.snframe.domain.Course.TCourse;
import com.server.questionbank.snframe.domain.User.TUser;
import com.server.questionbank.snframe.mapper.Course.TChapterMapper;
import com.server.questionbank.snframe.service.CourseService.TChapterService;
import com.server.questionbank.snframe.service.CourseService.TCourseService;
import com.server.questionbank.snframe.service.UsersService.UsersService;
import com.server.questionbank.snframe.util.MinIo.MinIoBucket;
import com.server.questionbank.snframe.util.MinIo.MinIoFactory;
import com.server.questionbank.snframe.util.MinIo.ProgressInputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class TChapterServiceImpl implements TChapterService {
    @Autowired
    private TChapterMapper chapterMapper;
    @Autowired
    private MinIoFactory minIoFactory;
    @Autowired
    private UsersService usersService;
    @Autowired
    private TCourseService tCourseService;
    @Autowired
    private StringRedisTemplate redisTemplate;

    // 获取章节列表
    @Override
    public List<TChapter> getChapterList(Long courseId) {
        return chapterMapper.getChapterList(courseId);
    }

    // 获取章节信息
    @Override
    public TChapter getChapterInfo(Long chapterId) {
        return chapterMapper.getChapterInfo(chapterId);
    }

    // 获取课时列表
    @Override
    public List<TLessons> getLessonList(Long chapterId) {
        return chapterMapper.getLessonList(chapterId);
    }

    // 获取课时信息
    @Override
    public TLessons getLessonInfo(Long lessonsId) {
        return chapterMapper.getLessonInfo(lessonsId);
    }

    // 获取课时资源
    @Override
    public List<LessonsResource> getLessonResource(Long lessonsId) {
        return chapterMapper.getLessonResource(lessonsId);
    }

    // 获取课时资源信息
    @Override
    public LessonsResource getLessonResourceInfo(Long resourceId) {
        return chapterMapper.getLessonResourceInfo(resourceId);
    }

    // 更新章节信息
    @Override
    public Boolean updateChapters(Long courseId, List<UpdateChapter> updateChapters, Long updateBy) {
        try {
            List<Long> deleteLessonList = new ArrayList<>();
            List<UpdateLesson> updateLessonList = new ArrayList<>();
            List<UpdateLesson> addLessonList = new ArrayList<>();

            // === 章节处理 ===
            List<TChapter> dbChapters = getChapterList(courseId);

            DiffResult<UpdateChapter> chapterDiff = diffItems(
                    dbChapters,
                    updateChapters,
                    UpdateChapter::getChapterId,
                    item -> ((TChapter) item).getChapterId()
            );

            System.out.println("更新章节：" + chapterDiff.toUpdate);
            if (!updateChapter(chapterDiff.toUpdate, updateBy)) return false;

            System.out.println("新建章节：" + chapterDiff.toAdd);
            if (!createChapter(courseId, chapterDiff.toAdd, updateBy)) return false;

            // === 课时处理 ===
            for (UpdateChapter chapter : updateChapters) {
                Long chapterId = chapter.getChapterId();
                List<TLessons> dbLessons = getLessonList(chapterId);
                List<UpdateLesson> frontendLessons = chapter.getLessons();

                // 写回章节ID
                frontendLessons.forEach(lesson -> {lesson.setChapterId(chapterId);});

                DiffResult<UpdateLesson> lessonDiff = diffItems(
                        dbLessons,
                        frontendLessons,
                        UpdateLesson::getLessonsId,
                        item -> ((TLessons) item).getLessonsId()
                );

                deleteLessonList.addAll(lessonDiff.toDelete);
                updateLessonList.addAll(lessonDiff.toUpdate);
                addLessonList.addAll(lessonDiff.toAdd);
            }

            // 统一判断新增中有旧 ID 的课时（即跨章节移动的情况）
            Set<Long> deleteSet = new HashSet<>(deleteLessonList);
            Iterator<UpdateLesson> iter = addLessonList.iterator();
            while (iter.hasNext()) {
                UpdateLesson lesson = iter.next();
                Long lessonId = lesson.getLessonsId();
                if (lessonId != null && deleteSet.contains(lessonId)) {
                    updateLessonList.add(lesson);
                    iter.remove();
                    deleteSet.remove(lessonId);
                }
            }
            deleteLessonList.clear();
            deleteLessonList.addAll(deleteSet);

            System.out.println("删除课时：" + deleteLessonList);
            if (!deleteLesson(deleteLessonList)) return false;

            System.out.println("更新课时：" + updateLessonList);
            if (!updateLesson(updateLessonList, updateBy)) return false;

            System.out.println("新增课时：" + addLessonList);
            if (!createLesson(addLessonList, updateBy)) return false;

            // === 最后删除章节（防止课时操作出错） ===
            System.out.println("删除章节：" + chapterDiff.toDelete);
            if (!deleteChapter(chapterDiff.toDelete)) return false;

            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    // 更新课时信息
    @Override
    public Boolean updateLessonResource(Long lessonId, List<LessonsResource> lessonsResourceList, Long updateBy) {
        try {
            // === 章节处理 ===
            List<LessonsResource> dbLessonsResource = getLessonResource(lessonId);
            lessonsResourceList = lessonsResourceList.stream().map(lessonsResource -> {
                lessonsResource.setLessonsId(lessonId);
                return lessonsResource;
            }).collect(Collectors.toList());

            DiffResult<LessonsResource> LessonsResourceDiff = diffItems(
                    dbLessonsResource,
                    lessonsResourceList,
                    LessonsResource::getResourceId,
                    item -> ((LessonsResource) item).getResourceId()
            );

            System.out.println("更新章节：" + LessonsResourceDiff.toUpdate);
            for (LessonsResource resource : LessonsResourceDiff.toUpdate)
                if (chapterMapper.updateLessonResource(resource) < 0) return false;

            System.out.println("新建章节：" + LessonsResourceDiff.toAdd);
            for (LessonsResource resource : LessonsResourceDiff.toAdd)
                if (chapterMapper.createLessonResource(resource) < 0) return false;

            System.out.println("删除课时：" + LessonsResourceDiff.toDelete);
            for (Long resourceId : LessonsResourceDiff.toDelete)
                if (chapterMapper.deleteLessonResource(resourceId) < 0) return false;
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    // 上传课时资源
    @Override
    public void uploadFlie(MultipartFile file, Long courseId, Long chapterId, Long lessonsId, LessonsResource lessonsResource) throws Exception {
        MinIoBucket minIoBucket = minIoFactory.openBucket("course");

        String contentType = file.getContentType();
        long size = file.getSize();

        lessonsResource.setResourceUrlName(file.getOriginalFilename());
        String filePath = (courseId + "/chapters/" + chapterId  +
                "/lessons/" + lessonsId + "/" + lessonsResource.getResourceId() + "_" + lessonsResource.getResourceUrlName());

        // 上传文件
        try (InputStream inputStream = file.getInputStream()) {
            // 使用自定义的 ProgressInputStream 来计算进度
            ProgressInputStream.ProgressListener progressListener = progress -> {};

            try (ProgressInputStream progressInputStream = new ProgressInputStream(
                    inputStream, size, progressListener,
                    "upload_lessons_resource_" + lessonsResource.getResourceId(), redisTemplate)) {
                minIoBucket.uploadFile(filePath, progressInputStream, contentType, size);
            }
        }

        lessonsResource.setResourceUrl(filePath);
        if (chapterMapper.updateLessonResource(lessonsResource) < 0) throw new Exception("更新课时资源失败");
    }

    // 更新章节
    public class DiffResult<T> {
        public List<T> toAdd = new ArrayList<>();
        public List<T> toUpdate = new ArrayList<>();
        public List<Long> toDelete = new ArrayList<>();
    }
    public <T> DiffResult<T> diffItems(
            List<?> dbItems,
            List<T> frontendItems,
            Function<T, Long> getIdFunc,
            Function<Object, Long> dbGetIdFunc
    ) {
        DiffResult<T> result = new DiffResult<>();

        // 数据库中有效 ID（非 null 且 > 0）
        Set<Long> dbIds = dbItems.stream()
                .map(dbGetIdFunc)
                .filter(id -> id != null && id > 0)
                .collect(Collectors.toSet());

        // 前端中有效 ID（非 null 且 > 0）
        Set<Long> frontendIds = frontendItems.stream()
                .map(getIdFunc)
                .filter(id -> id != null && id > 0)
                .collect(Collectors.toSet());

        // 删除项：数据库有，前端没有
        result.toDelete.addAll(dbIds.stream()
                .filter(id -> !frontendIds.contains(id))
                .collect(Collectors.toList()));

        // 更新项：前端 ID 有效，且数据库中存在
        for (T item : frontendItems) {
            Long id = getIdFunc.apply(item);
            if (id != null && id > 0 && dbIds.contains(id)) {
                result.toUpdate.add(item);
            }
        }

        // 新增项：ID 为 null、0 或不在数据库中
        for (T item : frontendItems) {
            Long id = getIdFunc.apply(item);
            if (id == null || id <= 0 || !dbIds.contains(id)) {
                result.toAdd.add(item);
            }
        }

        return result;
    }

    // 创建课时
    private Boolean createLesson(List<UpdateLesson> updateLessons, Long createBy) {
        try {
            for (UpdateLesson updateChapter : updateLessons) {
                if(chapterMapper.createLesson(updateChapter, createBy) <= 0)
                    return false;
            }
            return true;
        } catch (Exception e)
        {
            e.printStackTrace();
            return false;
        }
    }

    // 更新课时
    private Boolean updateLesson(List<UpdateLesson> updateLessons, Long updateBy) {
        try {
            for (UpdateLesson updateLesson : updateLessons) {
                if(chapterMapper.updateLesson(updateLesson, updateBy) <= 0)
                    return false;
            }
            return true;
        } catch (Exception e)
        {
            return false;
        }
    }

    // 删除课时
    private Boolean deleteLesson(List<Long> lessonIds) {
        try {
            for (Long lessonId : lessonIds) {
                if(chapterMapper.deleteLesson(lessonId) <= 0)
                    return false;
            }
            return true;
        } catch (Exception e)
        {
            return false;
        }
    }

    // 创建章节
    private Boolean createChapter( Long courseId, List<UpdateChapter> updateChapters, Long createBy) {
        try {
            for (UpdateChapter updateChapter : updateChapters) {
                if(chapterMapper.createChapter(courseId, updateChapter, createBy) <= 0)
                    return false;
            }
            return true;
        } catch (Exception e)
        {
            return false;
        }
    }

    // 更新章节
    private Boolean updateChapter(List<UpdateChapter> updateChapters, Long updateBy) {
        try {
            for (UpdateChapter updateChapter : updateChapters) {
                if(chapterMapper.updateChapter(updateChapter, updateBy) <= 0)
                    return false;
            }
            return true;
        } catch (Exception e)
        {
            return false;
        }
    }

    // 删除章节
    private Boolean deleteChapter(List<Long> chapterIds) {
        try {
            for (Long chapterId : chapterIds) {
                List<Long> lessonIds = chapterMapper.getLessonList(chapterId).stream()
                        .map(TLessons::getLessonsId)
                        .collect(Collectors.toList());
                for (Long lessonId : lessonIds) if(chapterMapper.deleteLesson(lessonId) <= 0) return false;
                if(chapterMapper.deleteChapter(chapterId) <= 0) return false;
            }
            return true;
        } catch (Exception e)
        {
            return false;
        }
    }
}
